package com.geek.service.impl;

import com.geek.bean.BaseRespVo;
import com.geek.bean.data.*;
import com.geek.bean.vo.CartAddVO;
import com.geek.bean.vo.CartCheckedVO;
import com.geek.bean.vo.CartUpdateVO;
import com.geek.mapper.*;
import com.geek.model.*;
import com.geek.service.AddressService;
import com.geek.service.CartService;
import com.geek.service.CouponService;
import com.geek.service.GrouponService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 小豪
 * @version 1.0
 * @description
 * @date 2024-06-17 16:49
 */
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private MarketCartMapper cartMapper;
    @Autowired
    private MarketGoodsMapper goodsMapper;
    @Autowired
    private MarketGoodsProductMapper productMapper;
    @Autowired
    private MarketAddressMapper addressMapper;
    @Autowired
    private MarketCouponMapper couponMapper;
    @Autowired
    private MarketCouponUserMapper couponUserMapper;
    @Autowired
    CouponService couponService;
    @Autowired
    GrouponService grouponService;
    @Autowired
    AddressService addressService;

    /**
     * 获得购车里的商品数量
     */
    @Override
    public long getGoodsCount(Integer userId) {
        return cartMapper.countGoods(userId);
    }

    /**
     * 购物车首页
     *
     * @param userId 用户Id
     */
    @Override
    public CartIndexData index(Integer userId) {
        List<MarketCart> cartList = this.userCartList(userId);
        CartStat cartTotal = CartStat.stat(cartList);
        CartIndexData data = new CartIndexData();
        data.setCartList(cartList);
        data.setCartTotal(cartTotal);
        return data;
    }

    public List<MarketCart> userCartList(Integer userId) {
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria().andDeletedEqualTo(false).andUserIdEqualTo(userId);
        return cartMapper.selectByExample(cartExample);
    }

    /**
     * 购物车中计算选中的商品
     *
     * @param userId 用户id
     */
    @Override
    public CartIndexData checked(Integer userId, CartCheckedVO checkedVO) {
        MarketCart cart = new MarketCart();
        if (checkedVO.getIsChecked() == 0) {
            cart.setChecked(false);
        }
        if (checkedVO.getIsChecked() == 1) {
            cart.setChecked(true);
        }
        List<Integer> productIds = checkedVO.getProductIds();
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria()
                .andProductIdIn(productIds)
                .andUserIdEqualTo(userId)
                .andDeletedEqualTo(false);
        cartMapper.updateByExampleSelective(cart, cartExample);
        return this.index(userId);
    }


    /**
     * 和购物车添加商品
     */
    @Override
    public BaseRespVo add(Integer userId, CartAddVO cartAddVO) {
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria().andUserIdEqualTo(userId)
                .andDeletedEqualTo(false)
                .andGoodsIdEqualTo(cartAddVO.getGoodsId())
                .andProductIdEqualTo(cartAddVO.getProductId());
        List<MarketCart> marketCarts = cartMapper.selectByExample(cartExample);
        // 根据goodsId查询货物
        MarketGoods marketGoods = goodsMapper.selectByPrimaryKey(cartAddVO.getGoodsId());
        // 根据productId查询specification
        MarketGoodsProduct goodsProduct = productMapper.selectByPrimaryKey(cartAddVO.getProductId());
        if (marketCarts.isEmpty()) {
            MarketCart marketCart = new MarketCart();
            // 取出goods中的属性设置给
            marketCart.setGoodsId(marketGoods.getId());
            marketCart.setGoodsName(marketGoods.getName());
            marketCart.setGoodsSn(marketGoods.getGoodsSn());
            marketCart.setNumber(cartAddVO.getNumber());
            marketCart.setPicUrl(marketGoods.getPicUrl());
            marketCart.setPrice(marketGoods.getRetailPrice());
            marketCart.setChecked(true);
            marketCart.setUserId(userId);
            marketCart.setAddTime(new Date());
            marketCart.setUpdateTime(new Date());
            marketCart.setDeleted(false);
            marketCart.setProductId(cartAddVO.getProductId());
            marketCart.setSpecifications(goodsProduct.getSpecifications());
            cartMapper.insertSelective(marketCart);
        } else {
            int newNumber = marketCarts.get(0).getNumber().intValue() + cartAddVO.getNumber().intValue();
            MarketCart updateCart = new MarketCart();
            updateCart.setId(marketCarts.get(0).getId());
            updateCart.setNumber((short) newNumber);
            updateCart.setUpdateTime(new Date());
            cartMapper.updateByPrimaryKeySelective(updateCart);
        }
        return BaseRespVo.ok(cartMapper.countGoods(userId));
    }

    /**
     * 快速下单
     *
     * @param userId    用户Id
     * @param goodsId   商品Id
     * @param number    数量
     * @param productId 产品Id
     */
    @Override
    public Integer fastAdd(Integer userId, Integer goodsId, Short number, Integer productId) {
        CartAddVO cartAddVO = new CartAddVO();
        cartAddVO.setNumber(number);
        cartAddVO.setGoodsId(goodsId);
        cartAddVO.setProductId(productId);
        this.add(userId, cartAddVO);
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria().andGoodsIdEqualTo(goodsId)
                .andProductIdEqualTo(productId).andUserIdEqualTo(userId)
                .andDeletedEqualTo(false);
        List<MarketCart> cartList = cartMapper.selectByExample(cartExample);
        return cartList.get(0).getId();
    }

    /**
     * 计算购物车的订单信息
     */
    @Override
    public CartCheckoutData checkout(Integer userId, Integer cartId, Integer addressId,
                                     Integer couponId, Integer userCouponId,
                                     Integer grouponRuleId, BigDecimal freightMin, BigDecimal freightValue) {
        CartCheckoutData data = new CartCheckoutData();
        // 购物车里的商品
        List<MarketCart> marketCarts = getCheckedCarts(userId);
        data.setCheckedGoodsList(marketCarts);
        // 地址id是否为0
        if (addressId == 0) {
            MarketAddressExample addressExample = new MarketAddressExample();
            addressExample.createCriteria().andIsDefaultEqualTo(true)
                    .andUserIdEqualTo(userId).andDeletedEqualTo(false);
            List<MarketAddress> addressList = addressMapper.selectByExample(addressExample);
            data.setAddressId(addressId);
            Object checkedAddress = addressList == null || addressList.size() == 0 ? new AddressData(addressId) : addressList.get(0);
            data.setCheckedAddress(checkedAddress);
        } else {
            MarketAddress marketAddress = addressMapper.selectByPrimaryKey(addressId);
            data.setAddressId(addressId);
            data.setCheckedAddress(marketAddress);
        }
        // 计算选中商品的总钱数
        BigDecimal checkedGoodsAmount = sumCartCheckedAmount(marketCarts);
        // 优惠券数量
        MarketCouponUserExample couponUserExample = new MarketCouponUserExample();
        couponUserExample.createCriteria().andDeletedEqualTo(false)
                .andStatusEqualTo((short) 0).andUserIdEqualTo(userId);
        long countCoupon = couponUserMapper.countByExample(couponUserExample);
        data.setAvailableCouponLength((int) countCoupon);
        // 根据优惠券id判断是否选择优惠券，未选择则返回优惠券数量
        couponSumAmount(cartId, couponId, userCouponId, grouponRuleId, freightMin, freightValue, checkedGoodsAmount, data);
        return data;
    }

    @Override
    public ResponseCheckoutData cartCheckout(int userId, RequestOrderSubmitData submitData, Integer freightMin, Integer freightValue) {
        // checkedGoodsList
        List<MarketCart> cartList = this.findCheckedByUserId(userId);
        CartStat stat = CartStat.stat(cartList);
        BigDecimal resultPrice = null;
        // TotalPrice
        BigDecimal sum = stat.getGoodsAmount();

        ResponseCheckoutData data = getResponseCheckoutData(userId, submitData, freightMin, freightValue, sum, resultPrice, cartList);
        return data;
    }

    private void couponSumAmount(Integer cartId, Integer couponId, Integer userCouponId, Integer grouponRuleId, BigDecimal freightMin, BigDecimal freightValue, BigDecimal checkedGoodsAmount, CartCheckoutData data) {
        if (couponId != -1 && couponId != 0) {
            MarketCoupon marketCoupon = couponMapper.selectByPrimaryKey(couponId);
            BigDecimal min = marketCoupon.getMin() == null || marketCoupon.getMin().equals(BigDecimal.ZERO) ? BigDecimal.ZERO : marketCoupon.getMin();
            BigDecimal discount = marketCoupon.getDiscount() == null || marketCoupon.getDiscount().equals(BigDecimal.ZERO) ? BigDecimal.ZERO : marketCoupon.getDiscount();
            if (checkedGoodsAmount.compareTo(min) > 0 && checkedGoodsAmount.compareTo(freightMin) < 0) {
                BigDecimal actualPrice = checkedGoodsAmount.add(freightValue);
                BigDecimal endPrice = actualPrice.subtract(discount);
                data.setActualPrice(endPrice);
                data.setOrderTotalPrice(endPrice);
            } else {
                BigDecimal orderPrice = checkedGoodsAmount.subtract(discount);
                data.setActualPrice(orderPrice);
                data.setOrderTotalPrice(orderPrice);
            }
            data.setCartId(cartId);
            data.setCouponPrice(discount);
            data.setFreightPrice(BigDecimal.ZERO);
            data.setGoodsTotalPrice(checkedGoodsAmount);
            data.setGrouponRulesId(grouponRuleId);
            data.setUserCouponId(userCouponId);
            data.setCouponId(couponId);
            data.setGrouponPrice(BigDecimal.ZERO);
        } else {
            // couponId == -1
            sumAmountAndSetData(cartId, couponId, userCouponId, grouponRuleId, freightMin, freightValue, checkedGoodsAmount, data);
        }
    }

    // couponId == -1时计算商品总价是否超过运费，以及是否使用优惠券
    private static void sumAmountAndSetData(Integer cartId, Integer couponId, Integer userCouponId, Integer grouponRuleId, BigDecimal freightMin, BigDecimal freightValue, BigDecimal checkedGoodsAmount, CartCheckoutData data) {
        if (checkedGoodsAmount.compareTo(freightMin) > 0) {
            data.setFreightPrice(BigDecimal.ZERO);
            data.setActualPrice(checkedGoodsAmount);
            data.setOrderTotalPrice(checkedGoodsAmount);
        } else {
            BigDecimal endPrice = checkedGoodsAmount.add(freightValue);
            data.setFreightPrice(freightValue);
            data.setActualPrice(endPrice);
            data.setOrderTotalPrice(endPrice);
        }
        data.setCouponId(couponId);
        data.setCartId(cartId);
        data.setUserCouponId(userCouponId);
        data.setGrouponRulesId(grouponRuleId);
        data.setCouponPrice(BigDecimal.ZERO);
        data.setGoodsTotalPrice(checkedGoodsAmount);
        data.setGrouponPrice(BigDecimal.ZERO);
    }

    // 计算购物车中选中商品的数量
    private static BigDecimal sumCartCheckedAmount(List<MarketCart> marketCarts) {
        BigDecimal checkedGoodsAmount = marketCarts.stream().map(item -> {
            BigDecimal price = item.getPrice();
            int number = item.getNumber().intValue();
            return price.multiply(BigDecimal.valueOf(number));
        }).reduce(BigDecimal.ZERO, BigDecimal::add);
        return checkedGoodsAmount;
    }

    /**
     * 获取购物车中的被选中商品
     */
    private List<MarketCart> getCheckedCarts(Integer userId) {
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria().andDeletedEqualTo(false)
                .andUserIdEqualTo(userId)
                .andCheckedEqualTo(true);
        List<MarketCart> cartList = cartMapper.selectByExample(cartExample);
        List<MarketCart> marketCarts = cartList.stream().filter(MarketCart::getChecked).toList();
        return marketCarts;
    }

    /**
     * 立即购买
     */
    @Override
    public CartCheckoutData cartCheckoutFastAdd(Integer userId, Integer cartId, Integer addressId,
                                                Integer couponId, Integer userCouponId,
                                                Integer grouponRuleId, BigDecimal freightMin, BigDecimal freightValue) {
        CartCheckoutData data = new CartCheckoutData();
        // 查询购物车中被选中的物品
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria().andDeletedEqualTo(false)
                .andUserIdEqualTo(userId)
                .andIdEqualTo(cartId)
                .andCheckedEqualTo(true);
        List<MarketCart> cartList = cartMapper.selectByExample(cartExample);
        List<MarketCart> marketCarts = cartList.stream().filter(MarketCart::getChecked).toList();
        // 购物车里的商品
        data.setCheckedGoodsList(marketCarts);
        // 判断地址id是否为0
        if (addressId != 0) {
            MarketAddress marketAddress = addressMapper.selectByPrimaryKey(addressId);
            data.setAddressId(addressId);
            data.setCheckedAddress(marketAddress);
        } else {
            // 地址id为0查询默认地址
            MarketAddressExample addressExample = new MarketAddressExample();
            addressExample.createCriteria().andIsDefaultEqualTo(true)
                    .andUserIdEqualTo(userId).andDeletedEqualTo(false);
            List<MarketAddress> addressList = addressMapper.selectByExample(addressExample);
            Object checkedAddress = addressList == null || addressList.size() == 0 ? new HashMap<>().put("id", 0) : addressList.get(0);
            data.setAddressId(addressId);
            data.setCheckedAddress(checkedAddress);
        }
        // 计算选中商品的总钱数
        BigDecimal checkedGoodsAmount = sumCartCheckedAmount(marketCarts);
        // 查询优惠券数量
        MarketCouponUserExample couponUserExample = new MarketCouponUserExample();
        couponUserExample.createCriteria().andDeletedEqualTo(false)
                .andStatusEqualTo((short) 0).andUserIdEqualTo(userId);
        long countCoupon = couponUserMapper.countByExample(couponUserExample);
        data.setAvailableCouponLength((int) countCoupon);
        // 优惠券id ！= -1
        if (couponId != -1 && couponId != 0) {
            MarketCoupon marketCoupon = couponMapper.selectByPrimaryKey(couponId);
            BigDecimal min = marketCoupon.getMin() == null || marketCoupon.getMin().equals(BigDecimal.ZERO) ? BigDecimal.ZERO : marketCoupon.getMin();
            BigDecimal discount = marketCoupon.getDiscount() == null || marketCoupon.getDiscount().equals(BigDecimal.ZERO) ? BigDecimal.ZERO : marketCoupon.getDiscount();
            if (checkedGoodsAmount.compareTo(min) >= 0 && checkedGoodsAmount.compareTo(freightMin) >= 0) {
                BigDecimal actualPrice = checkedGoodsAmount.add(BigDecimal.ZERO);
                BigDecimal endPrice = actualPrice.subtract(discount);
                data.setActualPrice(endPrice);
                data.setOrderTotalPrice(endPrice);
            } else if (checkedGoodsAmount.compareTo(min) < 0 && checkedGoodsAmount.compareTo(freightMin) >= 0) {
                BigDecimal actualPrice = checkedGoodsAmount.add(BigDecimal.ZERO);
                BigDecimal endPrice = actualPrice.subtract(discount);
                data.setActualPrice(endPrice);
                data.setOrderTotalPrice(endPrice);
            } else if (checkedGoodsAmount.compareTo(min) >= 0 && checkedGoodsAmount.compareTo(freightMin) < 0) {
                BigDecimal actualPrice = checkedGoodsAmount.add(freightValue);
                BigDecimal endPrice = actualPrice.subtract(discount);
                data.setActualPrice(endPrice);
                data.setOrderTotalPrice(endPrice);
            } else if (checkedGoodsAmount.compareTo(min) >= 0 && checkedGoodsAmount.compareTo(freightMin) > 0) {
                BigDecimal actualPrice = checkedGoodsAmount.add(BigDecimal.ZERO);
                BigDecimal endPrice = actualPrice.subtract(discount);
                data.setActualPrice(endPrice);
                data.setOrderTotalPrice(endPrice);
            }
            data.setCartId(cartId);
            data.setCouponPrice(discount);
            data.setFreightPrice(freightValue);
            data.setGoodsTotalPrice(checkedGoodsAmount);
            data.setGrouponRulesId(grouponRuleId);
            data.setUserCouponId(userCouponId);
            data.setCouponId(couponId);
            data.setGrouponPrice(BigDecimal.ZERO);
        } else {
            // couponId == -1
            sumAmountAndSetData(cartId, couponId, userCouponId, grouponRuleId, freightMin, freightValue, checkedGoodsAmount, data);
        }
        return data;
    }

    /**
     * 购物车删除商品
     */
    @Override
    public void deleteByUserId(Integer userId, List<Integer> productIds) {
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria()
                .andDeletedEqualTo(false)
                .andUserIdEqualTo(userId)
                .andProductIdIn(productIds);
        MarketCart marketCart = new MarketCart();
        marketCart.setDeleted(true);
        cartMapper.updateByExampleSelective(marketCart, cartExample);
    }

    /**
     * 更新购物车商品数量
     */
    @Override
    public void update(Integer userId, CartUpdateVO updateVO) {
        MarketCart marketCart = new MarketCart();
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria().andProductIdEqualTo(updateVO.getProductId())
                .andIdEqualTo(updateVO.getId())
                .andGoodsIdEqualTo(updateVO.getGoodsId()).andUserIdEqualTo(userId);
        marketCart.setNumber(updateVO.getNumber());
        cartMapper.updateByExampleSelective(marketCart, cartExample);
    }

    @Override
    public List<MarketCart> findCheckedByUserId(int userId) {
        MarketCartExample example = new MarketCartExample();
        example.createCriteria().andDeletedEqualTo(false)
                .andUserIdEqualTo(userId)
                .andCheckedEqualTo(true);

        List<MarketCart> marketCarts = cartMapper.selectByExample(example);

        return marketCarts;
    }

    @Override
    public void deleteByCartId(Integer cartId) {
        cartMapper.deleteByPrimaryKey(cartId);
    }

    @Override
    public void deleteByListIds(List<MarketCart> cartList) {
        for (MarketCart cart : cartList) {
            this.deleteByCartId(cart.getId());
        }
    }

    @Override
    public MarketCart findById(Integer cartId) {
        return cartMapper.selectByPrimaryKey(cartId);
    }

    @Override
    public ResponseCheckoutData cartCountByFastadd(int userId, RequestOrderSubmitData submitData, Integer freightMin, Integer freightValue) {
        List<MarketCart> marketCart = this.findListById(submitData.getCartId());
        CartStat stat = CartStat.stat(marketCart);
        BigDecimal price = stat.getGoodsAmount();
        BigDecimal resultPrice = null;
        ResponseCheckoutData data = getResponseCheckoutData(userId, submitData, freightMin, freightValue, price, resultPrice, marketCart);
        return data;
    }

    @Override
    public List<MarketCart> findListById(Integer cartId) {
        MarketCartExample example = new MarketCartExample();
        example.createCriteria().andDeletedEqualTo(false)
                .andIdEqualTo(cartId);
        List<MarketCart> marketCarts = cartMapper.selectByExample(example);
        return marketCarts;
    }

    private ResponseCheckoutData getResponseCheckoutData(int userId, RequestOrderSubmitData submitData, Integer freightMin, Integer freightValue, BigDecimal sum, BigDecimal resultPrice, List<MarketCart> cartList) {
        // address
        Map<String, Object> map = new HashMap<>();
        Integer addressId = submitData.getAddressId();
        Integer couponId = submitData.getCouponId();
        Integer userCouponId = submitData.getUserCouponId();
        Integer grouponRulesId = submitData.getGrouponRulesId();
        if (addressId == 0) {
            map.put("id", 0);
        } else {
//            List<MarketAddress> addressList = addressService.findByAId(addressId);
//            List<Map<String, Object>> mapList = addressList.stream().map(marketAddress -> {
//                Map<String, Object> mapStream = new HashMap<>();
//                mapStream.put("addTime", marketAddress.getAddTime());
//                mapStream.put("addressDetail", marketAddress.getAddressDetail());
//                mapStream.put("areaCode", marketAddress.getAreaCode());
//                mapStream.put("city", marketAddress.getCity());
//                mapStream.put("county", marketAddress.getCounty());
//                mapStream.put("deleted", marketAddress.getDeleted());
//                mapStream.put("id", marketAddress.getId());
//                mapStream.put("isDefault", marketAddress.getIsDefault());
//                mapStream.put("name", marketAddress.getName());
//                mapStream.put("province", marketAddress.getProvince());
//                mapStream.put("tel", marketAddress.getTel());
//                mapStream.put("updateTime", marketAddress.getUpdateTime());
//                mapStream.put("userId", marketAddress.getUserId());
//                return mapStream;
//            }).collect(Collectors.toList());
//            map = mapList.get(0);
            MarketAddress marketAddress = addressService.findById(addressId);
            map.put("addTime", marketAddress.getAddTime());
            map.put("addressDetail", marketAddress.getAddressDetail());
            map.put("areaCode", marketAddress.getAreaCode());
            map.put("city", marketAddress.getCity());
            map.put("county", marketAddress.getCounty());
            map.put("deleted", marketAddress.getDeleted());
            map.put("id", marketAddress.getId());
            map.put("isDefault", marketAddress.getIsDefault());
            map.put("name", marketAddress.getName());
            map.put("province", marketAddress.getProvince());
            map.put("tel", marketAddress.getTel());
            map.put("updateTime", marketAddress.getUpdateTime());
            map.put("userId", marketAddress.getUserId());

        }
        // coupon
        Integer newCouponId = null;
        BigDecimal subCoupon = BigDecimal.valueOf(0);
        Integer length = null;
        if (couponId == -1) {
            length = couponService.countById(userId);
            newCouponId = -1;
        }else if (couponId > 0){
            newCouponId = couponId;
            Boolean flag = couponService.isPossess(userId, couponId);
            if (flag) {
                MarketCoupon coupon = couponService.findsById(couponId, sum);
                int result = sum.compareTo(coupon.getMin());
                if (result > 0) {
                    subCoupon = coupon.getDiscount();
                } else {
                    coupon.setDiscount(BigDecimal.ZERO);
                }
            }
        } else {
            newCouponId = 0;
        }
        // grouponPrice
        BigDecimal subGroupon = BigDecimal.valueOf(0);
        if (grouponRulesId != null && grouponRulesId > 0) {
            MarketGroupon groupon = grouponService.findById(grouponRulesId);
            Integer rulesId = groupon.getRulesId();
            MarketGrouponRules grouponRules = grouponService.findByGroupRulesId(rulesId);
            if (grouponRules != null) {
                subGroupon = grouponRules.getDiscount();
            }
        }
        // actualPrice and orderTotalPrice
        BigDecimal add = subGroupon.add(subCoupon);
        BigDecimal sumSubPrice = sum.subtract(add);

        // freightPrice
        BigDecimal freightPriceMin = new BigDecimal(freightMin.toString());
        BigDecimal freightPriceValue = new BigDecimal(freightValue.toString());
        BigDecimal freightPrice = null;
        if (sum.compareTo(freightPriceMin) > 0) {
            freightPrice = BigDecimal.valueOf(0);
            resultPrice = sum;
        } else {
            freightPrice = freightPriceValue;
            resultPrice = sumSubPrice.subtract(freightPrice);
        }
        // 返回值
        ResponseCheckoutData data = ResponseCheckoutData.builder()
                .actualPrice(resultPrice)
                .addressId(addressId)
                .availableCouponLength(length)
                .cartId(submitData.getCartId())
                .checkedAddress(map)
                .checkedGoodsList(cartList)
                .couponId(newCouponId)
                .couponPrice(subCoupon)
                .freightPrice(freightPrice)
                .goodsTotalPrice(sum)
                .grouponPrice(subGroupon)
                .grouponRulesId(grouponRulesId)
                .orderTotalPrice(resultPrice)
                .userCouponId(userCouponId)
                .build();
        return data;
    }
}
